
package com.iss.umservice.common;

import java.security.Key;
import java.security.KeyFactory;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Scanner;

import javax.crypto.Cipher;

import org.apache.commons.codec.binary.Hex;

import com.sun.org.apache.xerces.internal.impl.dv.util.Base64;


public class RSAEncript
{
    /** RSA加密算法 */
    public final static String ALGORITHM_RSA = "RSA";
    
    /** 字符集 */
    public final static String ENCODING = "UTF-8";
    
    /** 公钥 */
    public final static String PUBLIC_KEY = "publickey";
    
    /** 私钥 */
    public final static String PRIVATE_KEY = "privatekey";
    
    /** 公钥分割长度 */
    public final static int PUBLIC_LENGTH_1024 = 53 * 2;
    
    /** 私钥分割长度 */
    public final static int PRIVATE_LENGTH_1024 = 128 * 2;
    
    /**
     * 
     * <p>
     * [功能简述] 公钥加密
     * <p>
     * <p>
     * [详细描述] 公钥加密
     * </p>
     * 
     * @param date
     * @param key
     * @return String
     * @throws Exception [参数说明]
     * @exception throws [违例类型] [违例说明]
     * @see [类、类#方法、类#成员]
     */
    public static String encode(String date, String key) throws Exception
    {
        X509EncodedKeySpec x509 = new X509EncodedKeySpec(Base64.decode(key));
        KeyFactory kf = KeyFactory.getInstance(ALGORITHM_RSA);
        Key k = kf.generatePublic(x509);
        Cipher c = Cipher.getInstance(ALGORITHM_RSA);
        c.init(c.ENCRYPT_MODE, k);
        byte[] bytes = c.doFinal(date.getBytes(ENCODING));
        return new String(Hex.encodeHex(bytes));
    }
    
    /**
     * 
     * <p>
     * [功能简述] 字符串分割与公钥加密
     * <p>
     * <p>
     * [详细描述] 1.分割字符串，53*2个字节一组； 2.对每组字符串进行公钥加密； 3.加密之后连接成一个字符串.
     * 4.明文长度不超过53位，加密后长度128，超过53*2位，加密后长度256
     * </p>
     * 
     * @param date
     * @param key
     * @return String
     * @throws Exception [参数说明]
     * @exception throws [违例类型] [违例说明]
     * @see [类、类#方法、类#成员]
     */
    public static String enc(String date, String key) throws Exception
    {
        int length = date.length();
        StringBuffer sb = new StringBuffer();
        int size = 0;
        if (length % PUBLIC_LENGTH_1024 == 0)
        {
            size = length / PUBLIC_LENGTH_1024;
            for (int i = 0; i < size; i++)
            {
                String s = date.substring(i * PUBLIC_LENGTH_1024, i
                        * PUBLIC_LENGTH_1024 + PUBLIC_LENGTH_1024);
                sb.append(encode(s, key));
            }
        }
        else
        {
            size = length / PUBLIC_LENGTH_1024 + 1;
            for (int i = 0; i < size; i++)
            {
                if (i == size - 1)
                {
                    String s = date.substring(i * PUBLIC_LENGTH_1024, length);
                    sb.append(encode(s, key));
                    break;
                }
                String s = date.substring(i * PUBLIC_LENGTH_1024, i
                        * PUBLIC_LENGTH_1024 + PUBLIC_LENGTH_1024);
                sb.append(encode(s, key));
            }
        }
        String input = sb.toString();
        return input;
    }
    
    /**
     * 
     * <p>
     * [功能简述] 私钥解密
     * <p>
     * <p>
     * [详细描述] 私钥解密
     * </p>
     * 
     * @param date
     * @param key
     * @return String
     * @throws Exception [参数说明]
     * @exception throws [违例类型] [违例说明]
     * @see [类、类#方法、类#成员]
     */
    public static String decode(String date, String key) throws Exception
    {
        char[] ac = new char[date.length()];
        for (int i = 0; i < date.length(); i++)
        {
            ac[i] = date.charAt(i);
        }
        byte[] inputs = Hex.decodeHex(ac);
        
        PKCS8EncodedKeySpec pek = new PKCS8EncodedKeySpec(Base64.decode(key));
        KeyFactory kf = KeyFactory.getInstance(ALGORITHM_RSA);
        Key k = kf.generatePrivate(pek);
        Cipher c = Cipher.getInstance(ALGORITHM_RSA);
        c.init(c.DECRYPT_MODE, k);
        byte[] bytes = c.doFinal(inputs);
        return new String(bytes, ENCODING);
    }
    
    /**
     * 
     * <p>
     * [功能简述] 字符串分割与私钥解密
     * <p>
     * <p>
     * [详细描述] 1.分割字符串，128*2个字节一组； 2.对每组字符串进行私钥解密； 3.解析之后连接成一个字符串.
     * </p>
     * 
     * @param date
     * @param key
     * @return String
     * @throws Exception [参数说明]
     * @exception throws [违例类型] [违例说明]
     * @see [类、类#方法、类#成员]
     */
    public static String den(String date, String key) throws Exception
    {
        int length = date.length();
        StringBuffer sb = new StringBuffer();
        int size = 0;
        if (length % PRIVATE_LENGTH_1024 == 0)
        {
            size = length / PRIVATE_LENGTH_1024;
            for (int i = 0; i < size; i++)
            {
                String s = date.substring(i * PRIVATE_LENGTH_1024, i
                        * PRIVATE_LENGTH_1024 + PRIVATE_LENGTH_1024);
                sb.append(decode(s, key));
            }
        }
        else
        {
            size = length / PRIVATE_LENGTH_1024 + 1;
            for (int i = 0; i < size; i++)
            {
                if (i == size - 1)
                {
                    String s = date.substring(i * PRIVATE_LENGTH_1024, length);
                    sb.append(decode(s, key));
                    break;
                }
                String s = date.substring(i * PRIVATE_LENGTH_1024, i
                        * PRIVATE_LENGTH_1024 + PRIVATE_LENGTH_1024);
                sb.append(decode(s, key));
            }
        }
        String output = sb.toString();
        return output;
    }
    
    /**
     * 
     * <p>
     * [功能简述] 公钥解密
     * <p>
     * <p>
     * [详细描述] 公钥解密
     * </p>
     * 
     * @param date
     * @param key
     * @return String
     * @throws Exception [参数说明]
     * @exception throws [违例类型] [违例说明]
     * @see [类、类#方法、类#成员]
     */
    public static String decriptByPublicKey(String date, String key)
            throws Exception
    {
        char[] ac = new char[date.length()];
        for (int i = 0; i < date.length(); i++)
        {
            ac[i] = date.charAt(i);
        }
        byte[] inputs = Hex.decodeHex(ac);
        X509EncodedKeySpec x509 = new X509EncodedKeySpec(Base64.decode(key));
        KeyFactory kf = KeyFactory.getInstance(ALGORITHM_RSA);
        Key k = kf.generatePublic(x509);
        Cipher c = Cipher.getInstance(ALGORITHM_RSA);
        c.init(c.DECRYPT_MODE, k);
        byte[] bytes = c.doFinal(inputs);
        return new String(bytes);
    }
    
    /**
     * 
     * <p>
     * [功能简述] 私钥加密
     * <p>
     * <p>
     * [详细描述] 私钥加密
     * </p>
     * 
     * @param date
     * @param key
     * @return String
     * @throws Exception [参数说明]
     * @exception throws [违例类型] [违例说明]
     * @see [类、类#方法、类#成员]
     */
    public static String encriptByPrivateKey(String date, String key)
            throws Exception
    {
        PKCS8EncodedKeySpec pek = new PKCS8EncodedKeySpec(Base64.decode(key));
        KeyFactory kf = KeyFactory.getInstance(ALGORITHM_RSA);
        Key k = kf.generatePrivate(pek);
        Cipher c = Cipher.getInstance(ALGORITHM_RSA);
        c.init(c.ENCRYPT_MODE, k);
        byte[] bytes = c.doFinal(date.getBytes(ENCODING));
        return new String(Hex.encodeHex(bytes));
    }
    
    /**
     * <p>
     * [功能简述]
     * <p>
     * <p>
     * [详细描述]
     * </p>
     * 
     * @param args [参数说明]
     * @exception throws [违例类型] [违例说明]
     */
    public static void main(String[] args)
    {
        while (true)
        {
            try
            {
                System.out.println("");
                System.out.println("************************************************************************");
                System.out.println("*****************        GZT    RSA      加密         ********************");
                System.out.println("************************************************************************");
                
                System.out.println("请输入数字, 【1】：获取密钥和公钥   【2】：公钥加密    【3】：私钥解密 【其他】：退出");
                
                Scanner sc = new Scanner(System.in);
                
                String input = sc.nextLine();
                
                if ("1".equals(input))
                {
                    /*System.out.println("请选择 512、1024、2048");
                    
                    String input1 = sc.nextLine();
                    
                    if ((!"512".equals(input1)) && (!"1024".equals(input1))
                            && (!"2048".equals(input1)))
                    {
                        continue;
                    }
                    */
                    //initKey();
                    
                    continue;
                }
                else if ("2".equals(input))
                {
                    System.out.println("请输入需要加密字符串：");
                    String input1 = sc.nextLine();
                    System.out.println("请输入公钥串:");
                    String input2 = sc.nextLine();
                    System.out.println("加密结果:");
                    String result = enc(input1, input2.replaceAll("\n\t", ""));
                    System.out.println(result);
                }
                else if ("3".equals(input))
                {
                    System.out.println("请输入需要解密字符串：");
                    String input1 = sc.nextLine();
                    System.out.println("请输入密钥串:");
                    String input2 = sc.nextLine();
                    System.out.println("解密结果:");
                    String result = den(input1, input2.replaceAll("\n\t", ""));
                    System.out.println(result);
                }
                else
                {
                    System.out.println("程序终止...");
                    
                    System.exit(0);
                }
            }
            catch (Exception e)
            {
                continue;
            }
        }
    }
}